#!/usr/bin/env python
#
#       Script_tab.py
#       
#       Copyright 2009 Brandon Invergo <brandon@brandoninvergo.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import sys
import locale

try:
    import pygtk
    #tell pyGTK, if possible, that we want GTKv2
    pygtk.require("2.0")
except:
    #Some distributions come with GTK2, but not pyGTK
    pass

try:
    import gtk
    import gtk.glade
    
except:
    print "You need to install pyGTK or GTKv2 ",
    print "or set your PYTHONPATH correctly."
    print "try: export PYTHONPATH=",
    print "/usr/local/lib/python2.2/site-packages/"
    sys.exit(1)

from gtk.gdk import CONTROL_MASK, SHIFT_MASK
import pango
import gtksourceview
import Error_dialog
import MajeRe_Engine

class Script_tab:
    r_input_waiting = False
    open_brackets = ["{", "[", "("]
    closed_brackets = ["}", "]", ")"]
    bracket_counts = [0, 0, 0]
    command_history = [""]
    command_history_mark = -1
    
    def on_console_entry(self, widget, entry):
        """This function handles commands entered in the console input"""
        entry_text = entry.get_text()
        self.R_command(entry_text)
        entry.set_text('')        

    def on_script_key_event(self, widget, event):
        """This function handles key events sent from the script_buffer"""
        key = gtk.gdk.keyval_name(event.keyval)
        if event.state & CONTROL_MASK:
            # If Ctrl-Return is pressed, send a command to R and output
            # to the console
            if key == "Return":
                # If text is selected, split the selection by lines,
                # send each line individually to R, and output to the 
                # console
                if self.script_buffer.get_has_selection():
                    selection_bounds = self.script_buffer.get_selection_bounds()
                    selected_text = self.script_buffer.get_text(selection_bounds[0], \
                        selection_bounds[1])
                    selected_lines = selected_text.splitlines(False)
                    for line in selected_lines:
                        self.R_command(line)
                # ...otherwise, send the text in the current line of the
                # script editor
                else:
                    cursor_iter = self.script_buffer.get_iter_at_mark(self.script_buffer.get_insert())
                    cursor_line = cursor_iter.get_line()
                    line_iter = self.script_buffer.get_iter_at_line(cursor_line)
                    end_line_iter = line_iter.copy()
                    end_line_iter.forward_to_line_end()
                    script_entry = self.script_buffer.get_text(line_iter, \
                            end_line_iter)
                    script_entry = script_entry.lstrip('/t')
                    self.R_command(script_entry)
                    if end_line_iter.forward_line() == False:
                        self.script_buffer.insert(end_line_iter,"\n")
                        end_line_iter.forward_line()
                    self.script_buffer.place_cursor(end_line_iter)
                return True
        return False    
        
    def R_command(self, command):
        command = command.lstrip("\t")
        if self.r_input_waiting == False:
            command_output = '> ' + command + '\n'
        else:
            command_output = '... ' + command + '\n'
            self.chain_command = self.chain_command + command
        
        for i in range(0,len(self.open_brackets)):
            self.bracket_counts[i] = self.bracket_counts[i] + \
                command.count(self.open_brackets[i])
        for i in range(0,len(self.closed_brackets)):
            self.bracket_counts[i] = self.bracket_counts[i] - \
                command.count(self.closed_brackets[i])
        
        if len(filter(lambda x: x > 0, self.bracket_counts)) != 0:
            if self.r_input_waiting == False:
                self.r_input_waiting = True
                self.chain_command = command
        else:
            if self.r_input_waiting == True:
                self.r_input_waiting = False
                command = self.chain_command
                self.chain_command = ""
      
        enditer = self.console_buffer.get_end_iter()
        line_no = enditer.get_line()
        self.console_buffer.insert(enditer, command_output)
        bold_begin = self.console_buffer.get_iter_at_line(line_no)
        bold_end = bold_begin.copy()
        bold_end.forward_to_line_end()
        # Make the entry_text bold (keep the results normal)
        self.console_buffer.apply_tag_by_name("bold", bold_begin, bold_end)
        self.console_buffer.apply_tag_by_name("blue", bold_begin, bold_end)
      
        if self.r_input_waiting == False:
            self.command_history.insert(1, command)
            self.command_history_mark = 0
            err = False
            try:        
                res = self.main_window.do_R_command(command, True)    
            except MajeRe_Engine.REngException, error_msg:
                err = True
                res = error_msg.parameter
          
            if (err == True):
                #apply a red font tag to errors
                for line in res:
                    line_no = enditer.get_line()
                    self.console_buffer.insert(enditer, line)
                    red_begin = self.console_buffer.get_iter_at_line(line_no)
                    red_end = red_begin.copy()
                    red_end.forward_to_line_end()
                    self.console_buffer.apply_tag_by_name("red", red_begin, red_end)
                    while not red_end.is_end():
                        red_begin.forward_line()
                        red_end = red_begin.copy()
                        red_end.forward_to_line_end()
                        self.console_buffer.apply_tag_by_name("red", red_begin, red_end)
            else:
                for line in res:
                    self.console_buffer.insert(enditer, line)
            self.console_buffer.place_cursor(self.console_buffer.get_end_iter())
            self.console_output.scroll_mark_onscreen(self.console_buffer.get_insert())

    def on_console_key_event(self, widget, event):
        key = gtk.gdk.keyval_name(event.keyval)
        if key == "Up":
            self.command_history_mark = self.command_history_mark + 1
            if self.command_history_mark == len(self.command_history):
                self.command_history_mark = 0
            widget.set_text(self.command_history[self.command_history_mark])
            return True
        elif key == "Down":
            self.command_history_mark = self.command_history_mark - 1
            if self.command_history_mark < 0:
                self.command_history_mark = len(self.command_history) - 1
            widget.set_text(self.command_history[self.command_history_mark])
            return True
        return False
        
    def on_console_output_key_event(self, widget, event):
        key = gtk.dgk.keyval_name(event.keyval)
    
    def script_buffer_cut(self, clipboard):
        self.script_buffer.cut_clipboard(clipboard, True)
        
    def console_entry_cut(self):
        self.console_entry.cut_clipboard()
        
    def script_buffer_copy(self, clipboard):
        self.script_buffer.copy_clipboard(clipboard)
        
    def console_entry_copy(self):
        self.console_entry.copy_clipboard()
        
    def console_buffer_copy(self, clipboard):
        self.console_buffer.copy_clipboard(clipboard)
        
    def script_buffer_paste(self, clipboard):
        self.script_buffer.paste_clipboard(clipboard, None, True)
        
    def console_entry_paste(self):
        self.console_entry.paste_clipboard()
        
    def undo(self):
        if self.script_buffer.can_undo():
            self.script_buffer.undo()
        
    def redo(self):
        if self.script_buffer.can_redo():
            self.script_buffer.redo()
    
    def __init__(self, parent_window, glade_gui):        
        self.main_window = parent_window
        
        self.script_buffer = gtksourceview.SourceBuffer()
        self.console_buffer = gtk.TextBuffer()
        
        lang_man = gtksourceview.SourceLanguagesManager()
        langs = lang_man.get_available_languages()
        lang_names = [x.get_name() for x in langs]
        R_lang_index = lang_names.index("R")
        if R_lang_index:
            self.script_buffer.set_language(langs[R_lang_index])
        self.script_buffer.set_check_brackets(True)
        self.script_buffer.set_highlight(True)     
        self.console_buffer.create_tag("bold", weight=700)
        self.console_buffer.create_tag("blue", foreground="blue")
        self.console_buffer.create_tag("red", foreground="red")
        self.console_buffer.create_tag("grey", foreground="grey")
        
        # A GtkSourceView widget is added the hard way
        self.script_textview = gtksourceview.SourceView(self.script_buffer)
        self.script_textview.set_show_line_numbers(True)
        self.script_textview.set_auto_indent(True)
        self.script_textview.set_tabs_width(4)
        self.script_textview.set_smart_home_end(True)
        self.script_textview.set_highlight_current_line(True)
        self.script_textview.connect("key_press_event", self.on_script_key_event)
        self.script_scroll = glade_gui.get_widget("Script_scrolledwindow")
        self.script_scroll.add(self.script_textview)
        self.script_textview.modify_font(pango.FontDescription("monospace"))
        self.script_textview.show()
        
        # Set up the R console
        self.console_output = glade_gui.get_widget("R_console_output")
        self.console_output.set_buffer(self.console_buffer)
        self.console_output.modify_font(pango.FontDescription("monospace"))
        
        callbacks = {"on_R_console_entry_activate" : \
            (self.on_console_entry, glade_gui.get_widget("R_console_entry")), \
            "on_R_console_key_event" : self.on_console_key_event, \
            "on_R_console_output_key_press_event": self.on_console_output_key_event}
        glade_gui.signal_autoconnect(callbacks)
        
        self.console_entry = glade_gui.get_widget("R_console_entry")
